package pacman;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Pattern;

import sun.java2d.loops.DrawGlyphListAA.General;

import maze.Direction;
import maze.Location;
import maze.Maze;

public class CommandParser {
	
	private final boolean VERBOSE = true;
	
	private Game game;
	
	public CommandParser(Game game){
		this.setGame(game);
	}
	
	/**
	 * Parses all the info from a maze-file.
	 * Initializes the maze, sets the players on the possible positions and sets pacman on the given position
	 */
	public Game parseMaze(File file) throws IOException{
		Maze maze = getMaze(file);
		givePlayersPositions(file, maze);
		givePacmanPosition(file);
		return this.getGame();
	}
	
	/**
	 * Reads the maze.txt file and uses the PACMAN command to give Pacman it's starting position
	 */
	private void givePacmanPosition(File file) throws IOException {
		FileInputStream fstream = new FileInputStream(file);
		DataInputStream in = new DataInputStream(fstream);
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		String strLine;
		while ((strLine = br.readLine()) != null){
			String [] parts = partitionStringFile(strLine);
			if(parts[1].equals("PACMAN")){
				int [] coords = getCoordsFromString(parts[2]);
				getGame().getPacman().setLocation(new Location(coords[0], coords[1]));
			}
		}
	}

	/**
	 * Reads the maze.txt file and uses the POSITION commands
	 * to create the new players and give them their starting positions
	 * in the new maze.
	 */
	private void givePlayersPositions(File file, Maze maze) throws IOException {
		FileInputStream fstream = new FileInputStream(file);
		DataInputStream in = new DataInputStream(fstream);
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		String strLine;
		int playersWithPositions = 0;
		while ((strLine = br.readLine()) != null){
			System.out.println(strLine);
			String [] parts = partitionStringFile(strLine);
			if(parts[1].equals("POSITION")){
				int [] coords = getCoordsFromString(parts[2]);
				getGame().getGhosts()[playersWithPositions] = 
						new Ghost(new Location(coords[0], coords[1]),
								0, 
								"Player " + playersWithPositions);
				playersWithPositions++;
			}
		}
	}

	
	/**
	 * Reads the maze.txt file and uses the DISCOVER commands to create a maze
	 */
	private Maze getMaze(File file) throws NumberFormatException, IOException {
		FileInputStream fstream = new FileInputStream(file);
		DataInputStream in = new DataInputStream(fstream);
		BufferedReader br = new BufferedReader(new InputStreamReader(in));
		String strLine;
		Maze maze = new Maze(6);
		while ((strLine = br.readLine()) != null){
			System.out.println(strLine);
			String [] parts = partitionStringFile(strLine);
			if(parts[1].equals("DISCOVER")){
				int [] coords = getCoordsFromString(parts[2]);
				int n = Integer.parseInt(parts[3]);
				maze.write(coords[0], coords[1], Direction.NORTH, (char) (2-n), true);
				int o = Integer.parseInt(parts[4]);
				maze.write(coords[0], coords[1], Direction.EAST, (char) (2-o), true);
				int z = Integer.parseInt(parts[5]);
				maze.write(coords[0], coords[1], Direction.SOUTH, (char) (2-z), true);
				int w = Integer.parseInt(parts[6]);
				maze.write(coords[0], coords[1], Direction.WEST, (char) (2-w), true);
			}
		}
		in.close();
		return maze;
	}

	public void parseCommand(String command) throws IOException{
		String[] parts = partitionStringCommand(command);		
		if(parts[0].equals("JOIN")){
			game.processJOIN();
			if(VERBOSE){
				System.out.println("JOIN");
			}
			
		}else if(parts[1].equals("NAME")){
			game.processNAME(
					parts[0],		//Name
					parts[2]);		//Version
			if(VERBOSE){
				System.out.println("NAME\n" + 
						"Name: " + parts[0] + 
						"\nVersion: " + parts[2]);
			}
			
		}else if(parts[1].equals("POSITION")){
			int [] coords = getCoordsFromString(parts[2]);
			game.processPOSITION(
					parts[0],			//Name 
					coords[0],			//X
					coords[1]);			//Y
			if(VERBOSE){
				System.out.println("POSITION\n" +
						"Name: " + parts[0] + 
						"\nX: " + coords[0] + 
						"\nY: "+ coords[1]);
			}
					
		}else if(parts[1].equals("DISCOVER")){
			int [] coords = getCoordsFromString(parts[2]);
			game.processDISCOVER(
					parts[0],		//Name
					coords[0],		//X
					coords[1], 		//Y
					Integer.parseInt(parts[3]),		//NORTH
					Integer.parseInt(parts[4]),		//EAST
					Integer.parseInt(parts[5]),		//SOUTH
					Integer.parseInt(parts[6]));	//WEST
			if(VERBOSE){
				System.out.println("DISCOVER\n" + 
						"Name: " + parts[0] + 
						"\nX: " + coords[0] + 
						"\nY: " + coords[1] +
						"\nNORTH: " + Integer.parseInt(parts[3]) + 
						"\nEAST: " + Integer.parseInt(parts[4]) + 
						"\nSOUTH: " + Integer.parseInt(parts[5]) + 
						"\nWEST: " + Integer.parseInt(parts[6]));
			}
					
		}else if(parts[1].equals("BARCODE")){
			game.processBARCODE(
					parts[0],						//Name
					Integer.parseInt(parts[2]),		//Code
					Integer.parseInt(parts[3])); 	//Direction
			if(VERBOSE){
				System.out.println("BARCODE\n" + 
						"Name: " + parts[0] + 
						"\nCode: " + Integer.parseInt(parts[2]) + 
						"\nDirection: " + Integer.parseInt(parts[3])); 
			}
			
		}else if(parts[1].equals("PACMAN")){
			int [] coords = getCoordsFromString(parts[2]);
			game.processPACMAN(
					coords[0],		//X
					coords[1]);		//Y
			if(VERBOSE){
				System.out.println("PACMAN\n" + 
						"X: " + coords[0] + 
						"\nY: " + coords[1]);
			}
			
		}else if(parts[1].equals("CAPTURED")){
			game.processCAPTURED(parts[0]);		//Name
			if(VERBOSE){
				System.out.println("CAPTURED\n" +
						"Name: " + parts[0]);
			}
			
		}else if(parts[1].equals("PLAN")){
			ArrayList<Location> plan = new ArrayList<Location>();
			for(int i = 2; i< parts.length; i++){
				int [] coords = getCoordsFromString(parts[i]);
				plan.add(new Location(coords[0], coords[1]));
			}
			game.processPLAN(parts[0], plan);
			if(VERBOSE){
				System.out.println("PLAN\n" + 
						"Name: " + parts[0]);
				for(Location loc: plan){
					System.out.println("Step "+ plan.indexOf(loc) + ": " + loc.toString());
				}
			}
			
		}else if(parts[1].equals("CANCELPLAN")){
			game.processCANCELPLAN(parts[0]);
			if(VERBOSE){
				System.out.println("CANCELPLAN\n" + 
						"Name: " + parts[0]);
			}
			
		}else if(parts[1].equals("PING")){
			game.processPING(
					parts[0],		//Name
					parts[2], 		//Destination
					parts[3]);		//Message
			if(VERBOSE){
				System.out.println("PING\n" + 
						"Name: " + parts[0] +
						"\nDestination: " + parts[2] +
						"\nMessage: " + parts[3]);
			}
			
		}else if(parts[1].equals("PONG")){
			game.processPONG(
					parts[2], 		//Destination
					parts[3]);		//Message
			if(VERBOSE){
				System.out.println("PONG\n" + 
						"Destination: " + parts[2] +
						"\nMessage: " + parts[3]);
			}
		}
	}
	
	private int [] getCoordsFromString(String coord){
		String[] coords = Pattern.compile(",").split(coord);
		int [] result = new int[2];
		result[0] = Integer.parseInt(coords[0]);
		result[1] = Integer.parseInt(coords[1]);
		return result;
	}
	
	/**
	 * Partitions a string received by RabbitMQ. Standard delimiter is " "
	 */
	private String [] partitionStringCommand(String input){
		input = (String) input.substring(0, input.length()-1); // \n op einde verwijderen
		String[] parts = Pattern.compile(" +").split(input);
		return parts;
	}
	
	/**
	 * Partitions a line from a txt file. Standard delimiter is " "
	 */
	private String [] partitionStringFile(String input){
		input = (String) input.substring(0, input.length()-2); // \n op einde verwijderen
		String[] parts = Pattern.compile(" +").split(input);
		return parts;
	}
	
	public static void main(String [] args) throws IOException{

		
	}
	
	public Game getGame() {
		return game;
	}

	private void setGame(Game game) {
		this.game = game;
	}
}
